package com.bankcard.bininfo.loader;

import com.bankcard.bininfo.model.BinInfo;
import com.bankcard.bininfo.model.*;
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvValidationException;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class CsvBinInfoLoadStrategy implements BinInfoLoadStrategy {
    /**
     * Loads BIN information from a CSV input stream.
     *
     * <p>The CSV file is expected to have the following columns:</p>
     * <ol>
     *     <li>BIN</li>
     *     <li>Card Brand</li>
     *     <li>Card Type</li>
     *     <li>Card Level</li>
     *     <li>Issuer Name</li>
     *     <li>Issuer Short Name</li>
     *     <li>Issuer Website</li>
     *     <li>Issuer Phone</li>
     *     <li>Country Name</li>
     *     <li>Country Code A2</li>
     *     <li>Country Code A3</li>
     *     <li>Country Currency</li>
     * </ol>
     *
     * <p>Example of a CSV file:</p>
     * <pre>
     * BIN,Card Brand,Card Type,Card Level,Issuer Name,Issuer Short Name,Issuer Website,Issuer Phone,Country Name,Country Code A2,Country Code A3,Country Currency
     * 123456,VISA,CREDIT,PLATINUM,Example Bank,ExBank,www.example.com,+123456789,Example Country,EC,EXC,EXC
     * </pre>
     *
     * @param inputStream the input stream of the CSV file
     * @return a list of BIN information
     * @throws IOException if an I/O error occurs
     * @throws CsvValidationException if a CSV validation error occurs
     */
    @Override
    public List<BinInfo> loadBinInfo(InputStream inputStream) throws IOException, CsvValidationException {
        List<BinInfo> binInfoList = new ArrayList<>();
        try (CSVReader reader = new CSVReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            // Skip header
            reader.readNext();

            String[] line;
            while ((line = reader.readNext()) != null) {
                if (line.length == 12) { // Updated to include issuerShortName
                    CountryInfo countryInfo = new CountryInfo(line[7], line[8], line[9], line[10]);
                    IssuerInfo issuerInfo = new IssuerInfo(line[4], line[5], line[6], line[11], countryInfo);
                    BinInfo binInfo = new BinInfo.Builder(line[0])
                            .cardBrand(CardBrands.valueOf(line[1].toUpperCase()))
                            .cardType(CardType.valueOf(line[2].toUpperCase()))
                            .cardLevel(CardLevel.valueOf(line[3].toUpperCase()))
                            .issuerInfo(issuerInfo)
                            .build();
                    binInfoList.add(binInfo);
                }
            }
        }
        return binInfoList;
    }
}